package com.lyj.job.filter;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: LIUYANJIAO
 * Date: 2025-08-13
 * Time: 22:56
 */

import cn.hutool.core.text.AntPathMatcher;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.lyj.common.core.constants.CacheConstants;
import com.lyj.common.core.constants.HttpConstants;
import com.lyj.common.core.domain.LoginUser;
import com.lyj.common.core.domain.R;
import com.lyj.common.core.enums.ResultCode;
import com.lyj.common.core.enums.UserIdentity;
import com.lyj.common.core.utils.JwtUtils;
import com.lyj.job.properties.IgnoreWhiteProperties;
import com.lyj.redis.service.RedisService;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import org.springframework.http.MediaType;

import java.util.List;

import static cn.hutool.core.util.ReUtil.isMatch;

/**
 * 过滤器
 */
@Slf4j
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    // 排除过滤的 uri 白名单地址，在nacos自行添加
    @Autowired
    private IgnoreWhiteProperties ignoreWhite;

    @Value("${jwt.secret}")
    private String secret;

    @Autowired
    private RedisService redisService;
    private static final AntPathMatcher pathMatcher = new AntPathMatcher();
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String url = request.getURI().getPath();
        //白名单的所有接口，不需要进行身份认证
        if(matches(url,ignoreWhite.getWhites())){
            return chain.filter(exchange);
        }
        //开始进行身份认证

        //从请求中获得token
        String token = getToken(request);
        //如果token为空，认证失败
        if(StrUtil.isEmpty(token)){
            //令牌不能为空
        }
        //如果token解析为空或解析失败，认证失败
        Claims claims = null;
        try {
            claims = JwtUtils.parseToken(token,secret);
            if(claims == null){
                //令牌已过期或验证不正确
            }
        }catch (Exception e){
            //令牌已过期或验证不正确
        }
        //通过token解析的claims找到userKey,userKey，认证失败
        String userKey = JwtUtils.getUserKey(claims);
        if(StrUtil.isEmpty(userKey)){
            //令牌验证失败
        }
        //通过userKey找到tokenKey，若tokenKey为空，认证失败
        String tokenKey = getTokenKey(userKey);
        if(StrUtil.isEmpty(tokenKey)){
            //令牌已过期
        }

        //通过tokenKey获得redis中存储的信息，若信息不完整认证失败
        boolean isLogin = redisService.hasKey(tokenKey);
        if(!isLogin){
            //令牌已过期
        }

        //令牌验证成功
        //判断C端和B端身份
        LoginUser user = redisService.getCacheObject(getTokenKey(userKey), LoginUser.class);
        if (url.contains(HttpConstants.SYSTEM_URL_PREFIX) && !UserIdentity.ADMIN.getValue().equals(user.getIdentity())) {
            return unauthorizedResponse(exchange, "令牌验证失败");
        }
        if (url.contains(HttpConstants.FRIEND_URL_PREFIX) && !UserIdentity.ORDINARY.getValue().equals(user.getIdentity())) {
            return unauthorizedResponse(exchange, "令牌验证失败");
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return -200;//值越小 过滤器就越先被执行
    }
    /**
     * 查找指定url是否匹配指定匹配规则链表中的任意一个字符串
     *
     * @param url         指定url
     * @param patternList 需要检查的匹配规则链表
     * @return 是否匹配
     */
    private boolean matches(String url, List<String> patternList) {
        if (StrUtil.isEmpty(url) || CollectionUtils.isEmpty(patternList)) {
            return false;
        }
        //接口地址如果和白名单中其中一个地址匹配就返回true。 如果便利完白名单中所有的地址都没有匹配的返回false
        for (String pattern : patternList) {
            if (pathMatcher.match(pattern, url)) {
                return true;
            }
        }
        return false;
    }
    /**
     * 从请求头中获取请求token
     */
    private String getToken(ServerHttpRequest request) {
        String token = request.getHeaders().getFirst(HttpConstants.AUTHENTICATION);
        // 如果前端设置了令牌前缀，则裁剪掉前缀
        if (StrUtil.isNotEmpty(token) && token.startsWith(HttpConstants.PREFIX)) {
            token = token.replaceFirst(HttpConstants.PREFIX, StrUtil.EMPTY);
        }
        return token;
    }

    /**
     * 获取缓存key
     */
    private String getTokenKey(String token) {
        return CacheConstants.LOGIN_TOKEN_KEY + token;
    }


    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, String msg) {
        log.error("[鉴权异常处理]请求路径:{}", exchange.getRequest().getPath());
        return webFluxResponseWriter(exchange.getResponse(), msg, ResultCode.FAILED_UNAUTHORIZED.getCode());
    }

    //拼装webflux模型响应
    private Mono<Void> webFluxResponseWriter(ServerHttpResponse response, String msg, int code) {
        response.setStatusCode(HttpStatus.OK);
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        R<?> result = R.fail(code, msg);
        DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(result).getBytes());
        return response.writeWith(Mono.just(dataBuffer));
    }
}
